#include "teststdafx.h"
#include "stdafx.h"
#include <gtest/gtest.h>

#include "Business/Policy/ArbitrageOffsetBusiness.h"
#include "Utils/TimeoutNotifier.h"
#include "Utils/FastBlockQueue.h"
#include "Business/QueueContext.h"
#include "Repository/CancellationRepository.h"
#include "Repository/DealingRepository.h"
#include "Service/MarketStorage.h"
#include "Business/Customer.h"
#include "Business/Command.h"
#include "Business/ExchangeNotify.h"
#include "Business/RequestTimeout.h"

using namespace std;

typedef ArbitrageOffsetBusiness::Argument BusinessArgument;
typedef ArbitrageOffsetBusiness::Snapshot BusinessSnapshot;

class ArbitrageOffsetBusinessTest : public testing::Test
{
protected:

	virtual void SetUp()
	{
		HANDLE hQuit = ::CreateEvent(NULL,TRUE,FALSE,NULL);
		m_customer.reset(new Customer("","",""));
		m_customer->SetOrginalAmount(10000.00);
		m_requestQueue.reset(FastBlockQueue::Create(hQuit));
		m_businessQueue.reset(FastBlockQueue::Create(hQuit));
		m_uiQueue.reset(FastBlockQueue::Create(hQuit));
		m_highTimerQueue.reset(FastBlockQueue::Create(hQuit));
		m_waitTimerQueue.reset(FastBlockQueue::Create(hQuit));
		m_dealingRepository.reset(new DealingRepository());
		m_cancellationRepository.reset(new CancellationRepository());
		m_queueContext.reset(new QueueContext(*m_requestQueue,*m_businessQueue,*m_uiQueue,*m_highTimerQueue,*m_waitTimerQueue));
		m_timeoutNotifier.reset(new TimeoutNotifier());

		InitMarket();

		Band bearish(80,120,MORE_LOWER);
		Band bullish(180,140,MORE_UPPER);
		m_business.reset(
			new ArbitrageOffsetBusiness(*m_customer,
				BusinessArgument(ArbitrageContracts(0,1),false,10,bearish),
				m_marketStorage,
				*m_queueContext,
				*m_dealingRepository,
				*m_cancellationRepository
			)
		);
	}
	virtual void TearDown()
	{
	}
	void InitMarket()
	{
		m_marketStorage.Save(CreateBearishMarket0());
		m_marketStorage.Save(CreateBearishMarket1());
	}

	Market CreateBearishMarket0()
	{
		Variety variety("zn1010",10,10);
		double lastPrice = 18550;
		Prices buyPrices;
		buyPrices[0] = Price(18550,10);
		Prices sellPrices;
		sellPrices[0] = Price(18540,5);
		double upperLimit = 40000;
		double lowerLimit = 20000;
		double preSettlementPrice  = 20000;
		return Market(0,variety,lastPrice,0,buyPrices,sellPrices,upperLimit,lowerLimit,preSettlementPrice); 
	}
	Market CreateBearishMarket1()
	{
		Variety variety("zn1011",10,10);
		double lastPrice = 18690;
		Prices buyPrices;
		buyPrices[0] = Price(18690,2);
		Prices sellPrices;
		sellPrices[0] = Price(18680,2);
		double upperLimit = 40000;
		double lowerLimit = 20000;
		double preSettlementPrice  = 20000;
		return Market(1,variety,lastPrice,0,buyPrices,sellPrices,upperLimit,lowerLimit,preSettlementPrice); 
	}

	void OnCommand(Command::TYPE type)
	{
		Command cmd = {0};
		cmd.type = type;
		cmd.business = m_business.get();
		m_business->OnCommand(cmd);
	}

	Dealing* OnOrdered()
	{
		bool quitFlag = false;
		QueueItem const& item = m_queueContext->GetRequestQueue().Pop(quitFlag);
		Dealing* dealing = m_dealingRepository->Get(((Dealing*)item.data)->GetLocalId());
		dealing->OnOrdered(FT("%d",dealing->GetLocalId()));
		m_business->OnDealing(*dealing);
		return dealing;
	}

	void OnTrade(Dealing* dealing,int quantity)
	{
		Trade trade(*dealing,dealing->GetOrderPrice(),quantity,dealing->GetSystemNo());
		dealing->OnTrade(trade);
		m_business->OnTrade(trade);
	}

	void OnBeairshOffsetMarkets()
	{
		m_business->OnMarket(CreateBearishMarket1());
	}

	void ExpectSnapshot(char const* status,int majorQuantity,int minorQuantity)
	{
		EXPECT_EQ(1,m_queueContext->GetUIQueue().Size());
		bool quitFlag = false;
		QueueItem const& item = m_queueContext->GetUIQueue().Pop(quitFlag);
		EXPECT_EQ(QueueItem::COMMAND,item.type);
		Command const& cmd = *(Command*)item.data;
		EXPECT_EQ(Command::UI_UPDATE_BUSINESS_INFO,cmd.type);
		BusinessSnapshot const& snapshot = *(BusinessSnapshot*)cmd.data;
		EXPECT_EQ(majorQuantity,snapshot.GetMajorQuantity());
		EXPECT_EQ(minorQuantity,snapshot.GetMinorQuantity());
	}
	MarketStorage m_marketStorage;
	auto_ptr<FastBlockQueue> m_requestQueue;
	auto_ptr<FastBlockQueue> m_businessQueue;
	auto_ptr<FastBlockQueue> m_uiQueue;
	auto_ptr<FastBlockQueue> m_highTimerQueue;
	auto_ptr<FastBlockQueue> m_waitTimerQueue;
	auto_ptr<Customer> m_customer;
	auto_ptr<ArbitrageOffsetBusiness> m_business;
	auto_ptr<DealingRepository> m_dealingRepository;
	auto_ptr<CancellationRepository> m_cancellationRepository;
	auto_ptr<QueueContext> m_queueContext;
	auto_ptr<TimeoutNotifier> m_timeoutNotifier;

	void foo();
};

TEST_F(ArbitrageOffsetBusinessTest,BearishOffsetTest)/*
void ArbitrageOffsetBusinessTest::foo() /* */
{
	int quantity = 10;
	EXPECT_STREQ("editable",m_business->GetSnapshot().GetStatus());
	OnCommand(Command::START_COMMAND);
	EXPECT_STREQ("start",m_business->GetSnapshot().GetStatus());
	ExpectSnapshot("start",quantity,quantity);

	for (int i = 1; i <= 5; ++i)
	{
		OnBeairshOffsetMarkets();
		EXPECT_STREQ("minor offset sent",m_business->GetSnapshot().GetStatus());
		ExpectSnapshot("minor offset sent",quantity,quantity);

		Dealing* offsetDealing = OnOrdered();
		EXPECT_EQ(2,offsetDealing->GetOrderQuantity());

		EXPECT_STREQ("minor offset ordered",m_business->GetSnapshot().GetStatus());
		ExpectSnapshot("minor offset ordered",quantity,quantity);
		EXPECT_EQ(1,m_queueContext->GetRequestQueue().Size());

		bool quitFlag = false;
		QueueItem& item = m_queueContext->GetRequestQueue().Pop(quitFlag);
		EXPECT_EQ(QueueItem::CANCELLATION,item.type);

		OnTrade(offsetDealing,offsetDealing->GetOrderQuantity());
		ExpectSnapshot("minor offset ordered",quantity,quantity-2);

		m_business->OnDealing(*offsetDealing);
		EXPECT_STREQ("major offset sent",m_business->GetSnapshot().GetStatus());
		ExpectSnapshot("major offset sent",quantity,quantity-2);
		EXPECT_EQ(1,m_queueContext->GetRequestQueue().Size());

		offsetDealing = OnOrdered();
		EXPECT_EQ(2,offsetDealing->GetOrderQuantity());
		
		OnTrade(offsetDealing,offsetDealing->GetOrderQuantity());
		m_business->OnDealing(*offsetDealing);
		EXPECT_EQ(quantity-2,m_business->GetSnapshot().GetMajorQuantity());
	
		quantity -= 2;

		if (i < 5 )
		{
			EXPECT_STREQ("start",m_business->GetSnapshot().GetStatus());
			ExpectSnapshot("start",quantity,quantity);
		}
		else
		{
			EXPECT_STREQ("end",m_business->GetSnapshot().GetStatus());
			ExpectSnapshot("end",quantity,quantity);
		}
	}
}


TEST_F(ArbitrageOffsetBusinessTest,BearishOffsetCancelTest)/*
void ArbitrageOffsetBusinessTest::foo() /* */
{
	EXPECT_STREQ("editable",m_business->GetSnapshot().GetStatus());
	OnCommand(Command::START_COMMAND);
	EXPECT_STREQ("start",m_business->GetSnapshot().GetStatus());

	OnBeairshOffsetMarkets();
	EXPECT_STREQ("minor offset sent",m_business->GetSnapshot().GetStatus());

	Dealing* offsetDealing = OnOrdered();
	EXPECT_EQ(2,offsetDealing->GetOrderQuantity());

	EXPECT_STREQ("minor offset ordered",m_business->GetSnapshot().GetStatus());
	EXPECT_EQ(1,m_queueContext->GetRequestQueue().Size());

	bool quitFlag = false;
	QueueItem& item = m_queueContext->GetRequestQueue().Pop(quitFlag);
	EXPECT_EQ(QueueItem::CANCELLATION,item.type);

	offsetDealing->OnCancelSuccess(0);
	m_business->OnDealing(*offsetDealing);
	EXPECT_STREQ("start",m_business->GetSnapshot().GetStatus());
}

TEST_F(ArbitrageOffsetBusinessTest,UpdateArgumentTest)/*
void ArbitrageOffsetBusinessTest::foo() /* */
{
	EXPECT_STREQ("editable",m_business->GetSnapshot().GetStatus());

	Command cmd = {0};
	cmd.type = Command::UPDATE_ARGUMENT_COMMAND;
	cmd.business = m_business.get();
	BusinessArgument& argument = *(BusinessArgument*)cmd.data;
	argument = BusinessArgument(m_business->GetArgument().GetContracts(),true,
		m_business->GetArgument().GetQuantity(),
		Band(210,220,MORE_LOWER));
	m_business->OnCommand(cmd);
	EXPECT_EQ(Operation::OFFSET_TODAY,m_business->GetArgument().GetOffsetOperation());


	OnCommand(Command::START_COMMAND);
	EXPECT_STREQ("start",m_business->GetSnapshot().GetStatus());

	argument = BusinessArgument(m_business->GetArgument().GetContracts(),false,
		m_business->GetArgument().GetQuantity(),
		Band(210,220,MORE_LOWER));
	m_business->OnCommand(cmd);

	OnBeairshOffsetMarkets();
	EXPECT_STREQ("start",m_business->GetSnapshot().GetStatus());

	argument = BusinessArgument(m_business->GetArgument().GetContracts(),true,
		m_business->GetArgument().GetQuantity(),
		Band(80,120,MORE_LOWER));
	m_business->OnCommand(cmd);	
	OnBeairshOffsetMarkets();
	EXPECT_STREQ("minor offset sent",m_business->GetSnapshot().GetStatus());
	bool quitFlag = false;
	QueueItem const& item = m_queueContext->GetRequestQueue().Pop(quitFlag);
	Dealing* dealing = m_dealingRepository->Get(((Dealing*)item.data)->GetLocalId());
	EXPECT_EQ(Operation::OFFSET_TODAY,dealing->GetOperation());
}